package com.example.mapkittest

import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Looper
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.example.mapkittest.databinding.ActivityMainBinding
import com.example.mapkittest.models.Landmark
import com.example.mapkittest.viewmodels.LandmarkViewModel
import com.google.android.gms.location.*
import com.yandex.mapkit.Animation
import com.yandex.mapkit.MapKitFactory
import com.yandex.mapkit.geometry.Point
import com.yandex.mapkit.map.*
import com.yandex.mapkit.map.Map
import com.yandex.runtime.image.ImageProvider
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var map: Map
    private val viewModel: LandmarkViewModel by viewModels()
    private lateinit var fusedClient: FusedLocationProviderClient
    private lateinit var userPlaceMark: PlacemarkMapObject
    private var userLocation: Point = Point()
    private lateinit var pinsCollection: MapObjectCollection
    private val pinList: MutableList<PlacemarkMapObject> = mutableListOf()

    private val locationCallback = object : LocationCallback() {
        override fun onLocationResult(p0: LocationResult) {
            p0.lastLocation?.let {
                viewModel.updateUserLocation(Point(it.latitude, it.longitude))
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        fusedClient = LocationServices.getFusedLocationProviderClient(this)
        MapKitFactory.initialize(this)

        checkPermissions()
        map = binding.mapView.mapWindow.map
        pinsCollection = map.mapObjects.addCollection()
        moveCamera(viewModel.position, viewModel.zoom, viewModel.azimuth, viewModel.tilt)

        userPlaceMark = map.mapObjects.addPlacemark().apply {
            setIcon(ImageProvider.fromResource(baseContext, R.drawable.ic_user_location2))
        }
        lifecycleScope.launch {
            viewModel.userLocation.collect {
                userPlaceMark.geometry = it
                userLocation = it
            }
        }

        lifecycleScope.launch {
            viewModel.landmark.collect { landmarks ->
                updateLandmarks(landmarks)
            }
        }

        binding.zoomInButton.setOnClickListener { changeZoomByStep(ZOOM_STEP) }
        binding.zoomOutButton.setOnClickListener { changeZoomByStep(-ZOOM_STEP) }
        binding.userLocationButton.setOnClickListener {
            lifecycleScope.launch { moveCamera(userLocation) }
        }
    }

    private val placemarkTap = object : MapObjectTapListener {
        override fun onMapObjectTap(p0: MapObject, p1: Point): Boolean {
            val landmark = p0.userData as Landmark
            showPlacemarkInfo(landmark)
            return true
        }

    }

    private fun updateLandmarks(landmarks: List<Landmark>) {
        val imageProvider = ImageProvider.fromResource(baseContext, R.drawable.ic_pin2)
        pinsCollection.clear()
        pinList.clear()
        landmarks.forEach { landmark ->
            pinList.add(
                pinsCollection.addPlacemark().apply {
                    geometry = landmark.toPoint()
                    setIcon(imageProvider)
                    userData = landmark
                    addTapListener(placemarkTap)
                }
            )
        }
    }

    @SuppressLint("MissingPermission")
    private fun startLocation() {
        val request = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 1000).build()
        fusedClient.requestLocationUpdates(request, locationCallback, Looper.getMainLooper())
    }

    private fun showPlacemarkInfo(landmark: Landmark) {
        val intent = Intent(this, LandmarkInfoActivity::class.java).apply {
            putExtra(
                "result",
                "${landmark.name}\n${landmark.description}\nLatitude: ${landmark.latitude}\nLongitude: ${landmark.longitude}"
            )
        }
        startActivity(intent)
    }

    private fun checkPermissions() {
        if (REQUIRED_PERMISSIONS.all {
                ContextCompat.checkSelfPermission(
                    this, it
                ) == PackageManager.PERMISSION_GRANTED
            }) {
            startLocation()
        } else {
            registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { map ->
                if (map.values.all { it }) startLocation()
            }.launch(REQUIRED_PERMISSIONS)
        }
    }

    private fun moveCamera(value: Point, zoom: Float = 17f, azimuth: Float = 0f, tilt: Float = 0f) {
        map.move(CameraPosition(value, zoom, azimuth, tilt), SMOOTH_ANIMATION, null)
    }

    private fun changeZoomByStep(value: Float) {
        with(map.cameraPosition) {
            map.move(CameraPosition(target, zoom + value, azimuth, tilt), SMOOTH_ANIMATION, null)
        }
    }

    override fun onStart() {
        super.onStart()
        MapKitFactory.getInstance().onStart()
        binding.mapView.onStart()
    }

    override fun onStop() {
        binding.mapView.onStop()
        MapKitFactory.getInstance().onStop()
        fusedClient.removeLocationUpdates(locationCallback)
        super.onStop()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        with(viewModel) {
            position = map.cameraPosition.target
            tilt = map.cameraPosition.tilt
            zoom = map.cameraPosition.zoom
            azimuth = map.cameraPosition.azimuth
        }
    }

    companion object {
        private val REQUIRED_PERMISSIONS = arrayOf(
            android.Manifest.permission.ACCESS_FINE_LOCATION,
            android.Manifest.permission.ACCESS_COARSE_LOCATION
        )
        private const val ZOOM_STEP = 1f
        private val SMOOTH_ANIMATION = Animation(Animation.Type.SMOOTH, 1f)
    }
}